package olegroshka.src.com.bofa.olegroshka;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.InvalidPropertiesFormatException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import olegroshka.src.com.bofa.olegroshka.common.Visitor;
import olegroshka.src.com.bofa.olegroshka.filter.Filter;

public enum Configuration {

	INSTANCE;

	private static final Logger LOG = Logger.getLogger(Configuration.class.getName());
	private static final String MM_DD_YYYY = "MM/dd/yyyy";
	private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(MM_DD_YYYY);
	
	private final Properties properties = new Properties();
	
	Configuration() {
		load(System.getProperty("bofaTest.properties"));
	}
	
	@SuppressWarnings("serial")
	public Properties getProperties() {
		return new Properties(this.properties) {

			@Override
			public synchronized Object setProperty(String key, String value) {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized void load(Reader reader) throws IOException {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized void load(InputStream inStream) throws IOException {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized Object put(Object key, Object value) {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized Object remove(Object key) {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized void putAll(Map<? extends Object, ? extends Object> t) {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}

			@Override
			public synchronized void clear() {
				throw new UnsupportedOperationException("Not supported - immutable Properties object");
			}
			
		};
	}

	public String getProperty(String key) {
		return properties.getProperty(key);
	}

	public void visitPropeties(Visitor<String> visitor, Filter<String> filter) {
		Set<Entry<Object, Object>> entrySet = properties.entrySet();
		for (Entry<Object, Object> entry : entrySet) {
			if (filter.accept((String) entry.getKey())) {
				visitor.visit((String) entry.getValue());
			}
		}
	}

	private void load(String propertyFilePath) {
		InputStream in = null;
		try {
			in = propertyFilePath != null && propertyFilePath.length() > 0 ? new FileInputStream(
					propertyFilePath) : ClassLoader.getSystemResourceAsStream("olegroshka/src/input/runtime.properties");
			if ( in == null ) {
				throw new IllegalStateException("Can not find default configuration - runtime.properties");
			} 
			properties.load(in);
		} catch (FileNotFoundException e) {
			LOG.log(Level.SEVERE, "Can't find cofiguration file: "
					+ propertyFilePath, e);
		} catch (IOException e) {
			LOG.log(Level.SEVERE, "Can't load cofiguration", e);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					LOG.log(Level.WARNING, "Can't close file reader", e);
				}
			}
		}

		// add/overwrite system properties
		properties.putAll(System.getProperties());
	}
	
	private Date getDate(String key) {
		Date date = null;
		try {
			date = DATE_FORMAT.parse(getProperty(key));
		} catch (ParseException e) {
			throw new IllegalArgumentException("Wrong date format, expected: " + MM_DD_YYYY, e);
		}
		return date;
	}
	 
	public Date getStartDate() {
		return getDate("start.date");
	}

	public Date getEndDate() {
		return getDate("end.date");
	}
}
